/** 
  *     练习 4-5 给计算器程序增加访问 sin、exp 与 pow 等库函数的操作。有关这些库函
  * 数的详细信息，参见附录 B.4 节中的头文件<math.h>。
**/


#include <stdio.h>
#include <stdlib.h>	/* for atof */
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAXOP 100	/* max size of operand or operator */
#define NUMBER '0'	/* signal that a number was found */

#define CMD '~'		// 命令符号，表示后面跟着的是命令
#define FUNC '$'	// 函数符号，表示后面跟着的是函数

int getop(char []);
void push(double);
double pop(void);
void printtop(void);
double copy(void);
double peek(void);
int swop(void);
int count(void);
int clear(void);

void command(char s[]);
void function(char s[]);

/* reverse Polish calculator */
int main()
{
	int type;
	double op2, op3;
	char s[MAXOP];
	
	while((type = getop(s)) != EOF)
	{
		switch(type)
		{
		case NUMBER:
			push(atof(s));
			break;
		case '+':
			push(pop() + pop());
			break;
		case '*':
			push(pop() * pop());
			break;
		case '-':
			op2 = pop();
			push(pop() - op2);
			break;
		case '/':
			op2 = pop();
			if(op2 != 0.0)
				push(pop() / op2);
			else 
				printf("error: zero divisor\n");
			break;
		case '%':
			op2 = pop();
			if(op2 != 0)
				push(fmod(pop(), op2));
			else 
				printf("error: zero divisor\n");
			break;
		case '\n':
		case '=':
			printf("\t%.8g\n", pop());
			break;
		case '~':
			command(s);
			break;
		case '$':
			function(s);
			break;
		default:
			printf("error: unknown command %s\n", s);
			break;	
		}
	}

	return 0;
}

/*************** 处理命令与调用函数 ***************/

void argerror(int, int);

// 根据 s 执行操作
void command(char s[])
{
	double op2;

	if(strstr(s, "copy") != NULL)
	{
		op2 = copy();
		if(op2 != 0)
			printf("%g to be copied\n", op2);
	}
	else if(strstr(s, "clear") != NULL)
	{
		op2 = clear();
		if(op2 != 0)
			printf("The %d elements were deleted\n", (int)op2);
	}
	else if(strstr(s, "print") != NULL)
	{
		printtop();
	}
	else if(strstr(s, "swop") != NULL)
	{
		swop();
	}
	else if(strstr(s, "del") != NULL)
	{
		op2 = pop();
		printf("%g deleted\n", op2);
	}
	else if(strstr(s, "count") != NULL)
	{
		printf("%d\n", count());
	}
	else 
		printf("error: unknown command %s\n", s);
}

/* 根据函数名 s 调用函数 */
void function(char s[])
{
	double op;

	if(strstr(s, "sin") != NULL)
	{
		if(count() >= 1)
			push(sin(pop()));
		else
			argerror(1, count());
	}
	else if(strstr(s, "exp") != NULL)
	{
		if(count() >= 1)
			push(exp(pop()));
		else
			argerror(1, count());
	}
	else if(strstr(s, "pow") != NULL)
	{
		if(count() >= 2)
		{
			op = pop();
			push(pow(pop(), op));
		}
		else
			argerror(2, count());
	}
	else 
		printf("error: unknown function name %s\n", s);
}

/* 输出参数不足错误信息，ac 为需要的参数个数。ac2 为实际参数数 */
void argerror(int ac, int ac2)
{
	printf("Expect %d parameters, %d elements in the stack\n", ac, ac2);
}

/******** 栈操作 *******/

// 栈的最大长度
#define MAXVAL 100	/* maximum depth of val stack */

int sp = 0;		/* next free stack position */
double val[MAXVAL];	/* value stack */
// 将 f 压入栈中
/* push: push f onto value stack */
void push(double f)
{
	if(sp < MAXVAL)
		val[sp++] = f;
	else 
		printf("error: stack full, can't push %g \n", f);
}

// 弹出栈顶元素
/* pop: pop and return top value from stack */
double pop(void)
{
	if(sp > 0)
		return val[--sp];
	else 
	{
		printf("error: stack empty\n");
		return 0.0;
	}
}

// 打印栈顶元素
void printtop(void)
{
	if(sp > 0)
		printf("%g \n", val[sp-1]);
	else
		printf("error: stack empty\n");	
}

// 复制栈顶元素 如果成功返回被赋值元素的值
double copy(void)
{
	double n;
	if(sp > 0)
	{
		push(n = val[sp - 1]);
		return n;
	}
	else
	{
		printf("error: stack empty\n");
		return 0.0;
	}
}

// 获得栈顶元素的值
double peek(void)
{
	if(sp > 0)
		return val[sp - 1];
	else 
		printf("error: stack empty\n");
	return 0.0;
}

/* 交换栈顶的两个元素 成功返回 1， 否则返回 0 */
int swop()
{
	double t;
	if(sp > 1)
	{
		t = val[sp - 1];
		val[sp - 1] = val[sp - 2];
		val[sp - 2] = t;
		return 1;
	}
	else 
	{
		printf("The number of elements in the stack is insufficient\n");
		return 0;
	}
}

/* 清空栈 返回被清空的元素数 */
int clear()
{
	int n;
	if(sp > 0)
	{
		n = sp;
		sp = 0;
		return n;
	}
	else 
	{
		printf("error: stack empty\n");
		return 0;
	}
}

/* 返回栈中元素的数量 */
int count(void)
{
	return sp;
}

/************ 获取字符 ***********/

int getch(void);
void ungetch(int);
int peekch(void);

/*
	将输入放进 s 中，
	类型 ---- 返回值
	数字 ---- NUMBER
	指令 ---- ‘~’
	函数名 -- ‘$’
	其他 ---- 原字符
*/
/* getop: get next character or numeric operand */
int getop(char s[])
{
	int i, c, c2;
	
	while((s[0] = c = getch()) == ' ' || c == '\t')		// 去除多余的空白字符
		;
	s[1] = '\0';
	
	i = 0;
	if(c == '~' || c == '$')				// 这是一个指令或函数
	{
		c2 = c;
		while(!isspace(c = getch()) && c != EOF)	// 将空白符前的字符看作 指令 或 函数名
			s[i++] = c;
		s[i] = '\0';
		return c2;
	}
	
	if(!isdigit(c) && c != '.' && c != '-' && c != '+')
		return c;	/* not a number */
	
	if(c == '-' || c == '+')
	{
		c2 = c;
		if(isdigit(s[++i] = c = getch()) || c == '.')
			s[i] = c;
		else 
		{
			if(c != EOF)
				ungetch(c);
			return c2;
		}
	}
	if(isdigit(c))		/* collect integer part */
		while(isdigit(s[++i] = c = getch()))
			;
	if(c == '.')
		while(isdigit(s[++i] = c = getch()))
			;
	s[i] = '\0';
	if(c != EOF)
		ungetch(c);
	return NUMBER;
}

#define BUFSIZE 100

// 缓存的字符数组
char buf[BUFSIZE];		/* buffer for ungetch */
// 缓存数组指针
int bufp = 0;			/* next free position in buf */

/* 弹出缓冲栈最上面的字符，若缓冲区为空，则返回控制台输入的字符 */
int getch(void)			/* get a (possibly pushed-back) character */
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}

/* 将 c 压入缓冲区栈 */
void ungetch(int c)		/* push character back on input */
{
	if(bufp >= BUFSIZE)
		printf("ungetch: too many characters\n");
	else
		buf[bufp++] = c;
}

/* 返回缓冲区栈中最上面的字符的值，若缓冲区为空，则返回控制台输入的字符并将其压入缓冲栈 */
int peekch(void)
{
	int c;
	if(bufp > 0)
		return buf[bufp -1];
	else
	{
		buf[bufp++] = c = getchar();
		return getchar();
	}
}

